# REST framework之序列化器
创建models.py表结构
from django.db import models class UserGroup(models.Model): title = models.CharField(max_length=32) class UserInfo(models.Model): user_type_choices = ( (1, '普通用户'), (2, 'VIP'), (3, 'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=64) group = models.ForeignKey('UserGroup') # 一对多 roles = models.ManyToManyField('Role') # 多对多 class UserToken(models.Model): # 用户储存用户的token user = models.OneToOneField(to='UserInfo') token = models.CharField(max_length=64) class Role(models.Model): title = models.CharField(max_length=32) # 执行数据库迁移,并进行填充数据
# 查询数据
# 使用原有的方法取出modles中的数据,并进行返回
from . import models
import json
class RoleView(APIView): # 全局以配置了解析器
def get(self,request,*args,**kwargs):
roles = models.Role.objects.all()
ret = json.dumps(roles) # 报错,因为json只能序列化python的数据类型,QuerySet是Django的数据类型
return HttpResponse(ret)
#解决方案:
class RoleView(APIView): # 全局以配置了解析器
def get(self,request,*args,**kwargs):
roles = models.Role.objects.all().values('id','title')
roles = list(roles) # 因为这里的values取出来的还是Queryset装的字典
ret = json.dumps(roles, ensure_ascii=False) # 通过这个参数可以防止传入的字符串进行ascii编码
return HttpResponse(ret)
# 1、使用RESTframework来取数据(对Queryset列表进行序列化,多个使用many=True)
from . import models
import json
from rest_framework import serializers
class RoleSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField() # title必须和models中的字段进行对应
class RoleView(APIView): # 全局以配置了解析器
def get(self,request,*args,**kwargs):
roles = models.Role.objects.all()
ser = RoleSerializer(instance=roles,many=True) # many表示传入的数据有多条
ret = json.dumps(ser.data, ensure_ascii=False) # ser.data 表示从数据库中查出的对象role进行了Roleseralizer序列化后的字典
return HttpResponse(ret) #[{"id": 1, "title": "医生"}, {"id": 2, "title": "学生"}]
--------------------------------------------------------------------
# url.py文件中
urlpatterns = [
url(r'(?P<version>[v1|v2]+)/users/$',views.UsersView.as_view(),name='uuu'),
url(r'(?P<version>[v1|v2]+)/parser/$',views.ParserView.as_view()),
url(r'(?P<version>[v1|v2]+)/roles/$',views.RoleView.as_view()),
]
小提示:
1、 roles = models.Role.objects.filter(title='医生') # 当针对Queryset类型时必须配置many=True,即使只有一个对象 2、 也就是说我们要取数据的时候,必须先写一个序列化类,字段要和相对应的models中的字段像对象,没有强硬的要求(在查询的时候)
# 2、对单独的表对象进行取数据(序列化单个对象时many=False)
class RoleSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField() # title必须和models中的字段进行对应
class RoleView(APIView): # 全局以配置了解析器
def get(self,request,*args,**kwargs):
roles = models.Role.objects.all().first()
ser = RoleSerializer(instance=roles,many=True) # many表示传入的数据有多条
ret = json.dumps(ser.data, ensure_ascii=False) # ser.data 表示从数据库中查出的对象role进行了Roleseralizer序列化后的有序字典
return HttpResponse(ret) #{"id": 1, "title": "医生"}
# 3、处理字段中含有choices选项显示对应的值
原始状态我们可以取出的字段是数据库中储存的值,如下:我们想得到对应得值
class UserInfoSerializer(serializers.Serializer): xxxx = serializers.CharField(source='user_type') # 配置source来字段字段,之后就可以任意该名 username = serializers.CharField() password = serializers.CharField() class UserinfoView(APIView): def get(self, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True) print(ser.data) #[OrderedDict([('username', '序号话'), ('password', '123')]), OrderedDict([('username', '民人接'), ('password', '123')])] ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # [OrderedDict([('xxxx', '1'), ('username', '序号话'), ('password', '123')]), OrderedDict([('xxxx', '2'), ('username', '民人接'), ('password', '123')])]
小提示:
之前我们说每个字段必须想对应models表中得每个字段,那是因为没有配置source选项,配置了后就可以重写自己得字段名了
方案一:通过source配置相应字段得处理方式(source='get_字段_display')
from rest_framework import serializers class UserInfoSerializer(serializers.Serializer): xxxx = serializers.CharField(source='user_type') ooo = serializers.CharField(source='get_user_type_display') # 相似于models中的get_字段_display,取出相应字段名后调用get方法 username = serializers.CharField() password = serializers.CharField() class UserinfoView(APIView): def get(self, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True) print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # [{"xxxx": "1", "ooo": "普通用户", "username": "序号话", "password": "123"}, {"xxxx": "2", "ooo": "VIP", "username": "民人接","password": "123"}]
# 4、处理关系管理字段(一对多)
方案一:
from rest_framework import serializers class UserInfoSerializer(serializers.Serializer): xxxx = serializers.CharField(source='user_type') ooo = serializers.CharField(source='get_user_type_display') # 相似于models中的get_字段_display,取出相应字段名后调用get方法 username = serializers.CharField() password = serializers.CharField() gp = serializers.CharField(source='group.title') # 通过点来获取值 gp1 = serializers.CharField(source='group') class UserinfoView(APIView): def get(self, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True) print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) #[{"xxxx": "1", "ooo": "普通用户", "username": "序号话", "password": "123", "gp": "A组", "gp1": "UserGroup object"}, {"xxxx":"2", "ooo": "VIP", "username": "民人接", "password": "123", "gp": "B组", "gp1": "UserGroup object"}]
# 5、处理多对多字段时
from rest_framework import serializers
class UserInfoSerializer(serializers.Serializer):
xxxx = serializers.CharField(source='user_type')
ooo = serializers.CharField(source='get_user_type_display') # 相似于models中的get_字段_display,取出相应字段名后调用get方法
username = serializers.CharField()
password = serializers.CharField()
gp = serializers.CharField(source='group.title') # 通过点来获取值
gp1 = serializers.CharField(source='group')
rls = serializers.CharField(source='roles.all') # 多对多时,反向点all,返回的时Queryset列表,里面都都是对象
class UserinfoView(APIView):
def get(self, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users, many=True)
print(ser.data)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
# [{"xxxx": "1", "ooo": "普通用户", "username": "序号话", "password": "123", "gp": "A组", "gp1": "UserGroup object", "rls": "<QuerySet [<Role: Role object>, <Role: Role object>]>"}, {"xxxx": "2", "ooo": "VIP", "username": "民人接", "password":"123", "gp": "B组", "gp1": "UserGroup object", "rls": "<QuerySet [<Role: Role object>]>"}]
小提示:
1、通过source配置相应得字段,可以解决一对多(正向,一对一)和choices字段去值得问题,但是涉及到多对多时,就不能做到更详细得处理了,只能返回对象 2、.all方法,只适用于关系管理对象字段上
# 更细力度得获取到多对多中,每个被关联对象得字段(通过SerializerMethodField)
from rest_framework import serializers class UserInfoSerializer(serializers.Serializer): xxxx = serializers.CharField(source='user_type') ooo = serializers.CharField(source='get_user_type_display') # 相似于models中的get_字段_display,取出相应字段名后调用get方法 username = serializers.CharField() password = serializers.CharField() gp = serializers.CharField(source='group.title') # 通过点来获取值 gp1 = serializers.CharField(source='group') # rls = serializers.CharField(source='roles.all') # 多对多时,反向点all,返回的时Queryset列表,里面都都是对象 rls = serializers.SerializerMethodField() # 自定义函数获取字段 def get_rls(self,row): # 自定义函数 role_obj_list = row.roles.all() ret =[] for item in role_obj_list: ret.append({'id':item.id,'title':item.title}) return ret class UserinfoView(APIView): def get(self, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True) print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) #[{"xxxx": "1", "ooo": "普通用户", "username": "序号话", "password": "123", "gp": "A组", "gp1": "UserGroup object", "rls":[{"id": 1, "title": "医生"}, {"id": 2, "title": "学生"}]}, {"xxxx": "2", "ooo": "VIP", "username": "民人接", "password": "123","gp": "B组", "gp1": "UserGroup object", "rls": [{"id": 3, "title": "元昊"}]}]
# 通过多张表处理一对多字段(多对多不行)
class Group1Serializer(serializers.Serializer): title = serializers.CharField(max_length=32) class UserInfoSerializer(serializers.ModelSerializer): group = Group1Serializer() class Meta: model = models.UserInfo # fields = '__all__' fields = ['id', 'username', 'password', 'group', 'roles']
# 万金油:ModelSerializer
# 除了上面通过写继承Serializer的类来取数据,我们还可以使用ModelSerializer来取数据,和我们的ModelForm很类似
class UserInfoSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo # 选择那一张表 fields = '__all__' # 取出所有字段,当然也可以使用列表['id','title'...] class UserinfoView(APIView): def get(self, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True) print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # [{"id": 1, "user_type": 1, "username": "序号话", "password": "123", "group": 1, "roles": [1, 2]}, {"id": 2, "user_type": 2,"username": "民人接", "password": "123", "group": 2, "roles": [3]}]
# 方案一:fields结合source解决一对多和choices问题
class UserInfoSerializer(serializers.ModelSerializer): ooo = serializers.CharField(source='get_user_type_display') # 结合source自定义字段 class Meta: model = models.UserInfo fields = ['id','username','ooo'] # 引入多对多字段 class UserinfoView(APIView): def get(self, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True) print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # [{"id": 1, "username": "序号话", "ooo": "普通用户"}, {"id": 2, "username": "民人接", "ooo": "VIP"}]
# **方案二:**通过SerializerMethodField()解决多对多问题
class UserInfoSerializer(serializers.ModelSerializer): ooo = serializers.CharField(source='get_user_type_display') # 结合source自定义字段 rls = serializers.SerializerMethodField() # 自定义显示格式 class Meta: model = models.UserInfo fields = ['id','username','ooo','rls'] # 引入多对多字段 def get_rls(self, row): # row就是拿到的一条数据,一个对象 role_obj_list = row.roles.all() ret = [] for item in role_obj_list: ret.append({'id':item.id,'tile':item.title}) return ret # [{"id": 1, "username": "序号话", "ooo": "普通用户", "rls": [{"id": 1, "tile": "医生"}, {"id": 2, "tile": "学生"}]}, {"id": 2,"username": "民人接", "ooo": "VIP", "rls": [{"id": 3, "tile": "元昊"}]}]
小提示:
点开ModelSerializer,源码的第一段就是一张map表,标识了数据库中的各自字段所对应的在ModelSerualizer的字段
**方案三:**自定义类
# 解决choices问题 class MyField(serializers.CharField): def to_representation(self, value): # value相当于我们取得某个字段 return value.title class UserInfoSerializer(serializers.ModelSerializer): xl = MyField(source='group') class Meta: model = models.UserInfo fields = ['id','username','xl'] # 引入多对多字段 # [{"id": 1, "username": "序号话", "xl": "A组"}, {"id": 2, "username": "民人接", "xl": "B组"}] ------------------------------------------------------------、 # 解决多对多问题 class MyField(serializers.CharField): def to_representation(self, value): ret = json.dumps(list(value.all().values('id','title')),ensure_ascii=False) # 当然我们可以再写一个serilizer序列化类,鸡肋 return ret class UserInfoSerializer(serializers.ModelSerializer): # ooo = serializers.CharField(source='get_user_type_display') # 结合source自定义字段 # rls = serializers.SerializerMethodField() # 自定义显示格式 xl = MyField(source='roles') class Meta: model = models.UserInfo fields = ['id','username','xl'] # 引入多对多字段
自定义字段来进行多对多的查询
class Animal(models.Model): name = models.CharField(max_length=50, default='') type = models.CharField(max_length=50, default='') country = models.ForeignKey(Country, blank=True, null=True) @property def country_area(self): return self.country.area -------------------------------------------------------- # 在序列化类中使用 class AnimalSerializer(serializers.Serializer): pk = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) type = serializers.CharField(max_length=50) country = serializers.PrimaryKeyRelatedField(read_only=True) country_area = serializers.FloatField(required=False, source='country_area’)
# 部分总结
1、写类
1.1、继承Serializer
class RoleSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField() # title必须和models中的字段进行对应
1.2、继承ModelSerializer
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = ['id','username'] # '__all__'
2、自定义字段
2.1、通过source:
a. choices字段:xxxx = serializers.CharField(source='user_type')
b. 一对多:gp = serializers.CharField(source='group.title')
2.2、通过SerializerMethodField()和自定义函数
...
def get_rls(self,row): # 自定义函数,get_字段, row就是整张表
role_obj_list = row.roles.all()
ret =[]
for item in role_obj_list:
ret.append({'id':item.id,'title':item.title})
return ret
2.3、自定义类
# 继续学习ModelSerializer:深度控制
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = '__all__'
depth = 1 # 没写这之前,我们得到的数据都是如group,roles这种涉及到一对多和多对多的字段都是取到的pk,这之后就可以获得多个每个关联对象的所有字段
class UserinfoView(APIView):
def get(self, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users, many=True)
print(ser.data)
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
# 所有结构
[
{
"id": 1,
"user_type": 1,
"username": "序号话",
"password": "123",
"group": {
"id": 1,
"title": "A组"
},
"roles": [
{
"id": 1,
"title": "医生"
},
{
"id": 2,
"title": "学生"
}
]
},
{
"id": 2,
"user_type": 2,
"username": "民人接",
"password": "123",
"group": {
"id": 2,
"title": "B组"
},
"roles": [
{
"id": 3,
"title": "元昊"
}
]
}
]
# 小提示
1、depth 表示该表中如果都关系管理对象,就打开该对象的所有字段,表示深度,还可以depth=2 2、官方建议depth=[0~10]
# 序列化时外键生成hyperlink
# 通过
HyperlinkedIdentityField
重写外键管理对象字段,生成动态url(必须关联一个对象)class UserInfoSerializer(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='gp') # 重写group,通过url别名生成路径,必须写别名,我们的url中的pk,系统默认也是取group中的pk,如果换个名字就报错了 class Meta: model = models.UserInfo # fields = '__all__' fields = ['id', 'username', 'password', 'group', 'roles'] depth = 0 # 默认为0 class UserinfoView(APIView): def get(self,request, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True,context={'request':request}) # 需要写context print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) class GourpSerializer(serializers.ModelSerializer): class Meta: model = models.UserGroup fields = '__all__' class GourpView(APIView): # 对每个组进行详细生成url def get(self,request, *args, **kwargs): pk = kwargs.get('pk') # 通过路径传入 obj = models.UserGroup.objects.filter(pk=pk).first() ser = GourpSerializer(instance=obj, many=False) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # url.py文件中 urlpatterns = [ ... url(r'(?P<version>[v1|v2]+)/userinfo/$',views.UserinfoView.as_view()), url(r'(?P<version>[v1|v2]+)/group/(?P<pk>\d+)/$',views.GourpView.as_view(),name = 'gp'), ] #[{"id": 1, "username": "序号话", "password": "123", "group": "http://127.0.0.1:8000/api/v1/group/1/", "roles": [1, 2]},{"id": 2, "username": "民人接", "password": "123", "group": "http://127.0.0.1:8000/api/v1/group/2/", "roles": [3]}]
# 小提示:
1、我们url中有一个pk参数,通过HyperlinkedIdentityField字段后面的别名参数生成url时,需要参数pk,默认是一当前user.pk传入的,显然不符合我们的要求,我们的group中只有两个组,用户只继承A组 2、对每一条数据进行序列化的时候,需要添加 ser = UserInfoSerializer(instance=users, many=True,context={'request':request})的context参数
# 升级版,修正url中的pk不对齐问题
class UserInfoSerializer(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='gp', # 指定url别名 lookup_field='group_id', # 指定查找字段,可能是以他为参数,不能是group(对象) lookup_url_kwarg='pk') # 指定参数名 class Meta: model = models.UserInfo # fields = '__all__' fields = ['id', 'username', 'password', 'group', 'roles'] depth = 0 class UserinfoView(APIView): def get(self,request, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True,context={'request':request}) # 需要写context print(ser.data) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # [{"id": 1, "username": "序号话", "password": "123", "group1":"http://127.0.0.1:8000/api/v1/group/1/", "roles": [1, 2]}, {"id": 2, "username": "民人接", "password": "123", "group1": "http://127.0.0.1:8000/api/v1/group/2/", "roles": [3]}]
# 小提示:
1、在序列化类中定义group1字段,其以group.id作为url中的参数出入别名为'gp'的url中,再生成json返回数据 group1 = serializers.HyperlinkedIdentityField(view_name='gp',source='group.id') 2、源码中再HyperlinkedIdentityField中第一句: look_up = 'pk' # 表示默认以pk字段为参数传入 view_name = None
# 序列化源码解析
**步骤一:**代码分析
class UserInfoSerializer(serializers.ModelSerializer): group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk') class Meta: model = models.UserInfo # fields = '__all__' fields = ['id', 'username', 'password', 'group', 'roles'] depth = 0 class UserinfoView(APIView): def get(self,request, *args, **kwargs): users = models.UserInfo.objects.all() ser = UserInfoSerializer(instance=users, many=True,context={'request':request}) ret = json.dumps(ser.data, ensure_ascii=False) return HttpResponse(ret) # 以上述视图类为例子: 1、url路径匹配带CBV,再get中对UserInfoSeriazer进行实例化,去该类中找构造函数init,所以往上走 --> ModelSerializer类,任然没有,再往上走 --> Serializer类,没有 --> BaseSerializer中找到__init__(),同时还有__new__方法,且先执行new方法,进行判断many参数 def __new__(cls, *args, **kwargs): if kwargs.pop('many', False): # 分析是否是一个Queryst列表 return cls.many_init(*args, **kwargs) return super().__new__(cls, *args, **kwargs) # 对单个对象进行处理,从Field那获取空间self,然后执行自己的init方法 def __init__(self, instance=None, data=empty, **kwargs): self.instance = instance # 传入的单个对象 if data is not empty: self.initial_data = data self.partial = kwargs.pop('partial', False) self._context = kwargs.pop('context', {}) # 传入参数 kwargs.pop('many', None) super().__init__(**kwargs) 2、打开many_init()函数,里面返回了 def many_init(cls, *args, **kwargs): ... list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer) #调用ListSeralizer进行处理 return list_serializer_class(*args, **list_kwargs) 3、回到序列化后我们调用,ser.data,点击查看源码 3.1 @property def data(self): ret = super().data # 调用了BaseSerializer中的data属性 return ReturnDict(ret, serializer=self) # 返回一个有序字典 3.2、打开父类的data属性:(用于对_data进行返回) def data(self): ... if not hasattr(self, '_data'): if self.instance is not None and not getattr(self, '_errors', None): # 我们再去choices时使用过to_repersentions,用于获取对象中的值 self._data = self.to_representation(self.instance) ... return self._data 3.3、查找自己的self.to_representation方法,顶层是一个抛异常,最终我们在Serializer中找到了 def to_representation(self, instance): """ Object instance -> Dict of primitive datatypes. """ ret = OrderedDict() fields = self._readable_fields # 可读字段,进行了过滤了字段 for field in fields: # 对我们自定义的所有字段,循环 try: # 调用CharField.get_attribute方法,instance就是我们传入的对象 attribute = field.get_attribute(instance) except SkipField: continue check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute if check_for_none is None: ret[field.field_name] = None else: ret[field.field_name] = field.to_representation(attribute) return ret 3.4、找到父父父类Field中的get_attrbute(self,instance) def get_attribute(self, instance): """ Given the *outgoing* object instance, return the primitive value that should be used for this field. """ try: return get_attribute(instance, self.source_attrs) # 这里的source就是我们传入的source进行切割的列表,如'group.id'->[group,id], 我们再点开get_attrbute方法 ... 3.5、在进入更内层的get_attribute() def get_attribute(instance, attrs): """ Similar to Python's built in `getattr(instance, attr)`, but takes a list of nested attributes, instead of a single attribute. Also accepts either attribute lookup on objects or dictionary lookups. """ # 循环传入的source列表[group,title],或则['get_user_type_display'] for attr in attrs: try: if isinstance(instance, Mapping): instance = instance[attr] else: instance = getattr(instance, attr) # 拿到一个对象字段,给instance except ObjectDoesNotExist: return None if is_simple_callable(instance): # 判断是否是可以调用的如get_user_type_display try: instance = instance() # 执行函数 ... return instance
# 小提示:
1、 many=True,将QuerySet列表交给ListSerializer处理 many=False ,将对象交给Serliazer处理 2、单个对象:self.to_representation Queryset时:self.to_representation
# 序列化请求数据校验
# 简单的从请求体中获取数据,并打印出form中的数据校验
class UserGroupSerializer(serializers.Serializer): titile = serializers.CharField(error_messages={'required':'标题不能为空'}) # 因为继承了Field,所以都有 class UserGourpView(APIView): def post(self,request, *args, **kwargs): print(request.body) # 必须再data之前使用,否则data后就没有body了,b'{\n"name":"alex"\n}' print(request.data) # 已经配置了解析器 {'name': 'alex'} ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return HttpResponse('提交数据') # url中 urlpatterns = [ ... url(r'(?P<version>[v1|v2]+)/usergroup/$',views.UserGourpView.as_view()), ] # 运行结果 {'titile': [ErrorDetail(string='标题不能为空', code='required')]}
# 自定义类进行内置校验器校验
class XXXValidator(object): def __init__(self, base): self.base = base # 传入的参数 def __call__(self, value): # 只要触犯实例化就会触发__call__方法 if not value.startswith(self.base): # 必须以base开头 message = '标题必须以 %s 开头.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): """ This hook is called by the serializer instance, prior to the validation call being made. """ # 执行验证之前调用,serializer_fields是当前字段对象 pass class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required':'标题不能为空'}, validators=[XXXValidator('中国'),]) class UserGourpView(APIView): def post(self,request, *args, **kwargs): print(request.body) # 必须再data之前使用,否则data后就没有body了,b'{\n"name":"alex"\n}' print(request.data) # 已经配置了解析器 {'name': 'alex'} ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return HttpResponse('提交数据')
补充:
当然可以通过函数进行内置校验器校验: def validate_title(value): if 'mjj' in value: raise serializers.ValidationError class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[validate_title,])
# 序列化的局部校验(钩子函数)
class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[]) def validate_title(self,value): # validate_字段名,用来局部验证,局部钩子 if 'mjj' in value: raise serializers.ValidationError return value class UserGourpView(APIView): def post(self,request, *args, **kwargs): print(request.body) # 必须再data之前使用,否则data后就没有body了,b'{\n"name":"alex"\n}' print(request.data) # 已经配置了解析器 {'name': 'alex'} ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return HttpResponse('提交数据')
# 序列化的全局钩子
class UserGroupSerializer(serializers.Serializer): title = serializers.CharField(error_messages={'required':'标题不能为空'},validators=[]) def validate_title(self,value): # validate_字段名,用来局部验证 if 'mjj' in value: raise serializers.ValidationError return value def validate(self, attrs): print(attrs) # OrderedDict([('title', 'mj')]) if attrs['title'] == '666': raise serializers.ValidationError #{'non_field_errors': [ErrorDetail(string='Invalid input.', code='invalid')]} return attrs class UserGourpView(APIView): def post(self,request, *args, **kwargs): print(request.body) # 必须再data之前使用,否则data后就没有body了,b'{\n"name":"alex"\n}' print(request.data) # 已经配置了解析器 {'name': 'alex'} ser = UserGroupSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return HttpResponse('提交数据')
# 使用extra_kwargs进行每个字段的扩展
class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): """ This hook is called by the serializer instance, prior to the validation call being made. """ # 执行验证之前调用,serializer_fields是当前字段对象 pass class ModelUserSerializer(serializers.HyperlinkedModelSerializer): ll = serializers.HyperlinkedIdentityField(view_name='xxxx') tt = serializers.CharField(required=False) class Meta: model = models.UserInfo fields = "__all__" list_serializer_class = serializers.ListSerializer extra_kwargs = { # 可以对每个字段进行配置,甚至read_only 'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}, 'url': {'view_name': 'xxxx'}, 'ut': {'view_name': 'xxxx'}, } class TestView(APIView): def get(self, request, *args, **kwargs): # # 序列化,将数据库查询字段序列化为字典 data_list = models.UserInfo.objects.all() ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request}) return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证 print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')